Snowflake の AWS PrivateLink 設定手順をまとめてみる #SnowflakeDB

Snowflake の AWS PrivateLink 設定手順をまとめてみる #SnowflakeDB

Clock Icon2024.09.10

はじめに

Snowflake における AWS PrivateLink 設定についてまとめておきたく記事としました。

前提

ここでは以下の環境で検証を行いました。

  • Snowflake
    • Business Ciritical
      • PrivateLink の設定には Business Ciritical 以上のエディションが必要
    • クラウドリージョン:AWS_US_EAST_1
  • AWS
    • Snowflake アカウントと同一のリージョンに VPC を作成
    • VPC の DNS 設定では以下を有効化済み
      • DNS 解決
      • DNS ホスト名
    • VPC 作成時にあわせて S3 へのゲートウェイ型のエンドポイントを作成
    • VPC 内のインスタンスから単一の Snowflake アカウントに PrivateLink で接続する

下図のような構成を目指します。

image

構成手順は以下に記載があります。本記事でもこちらの内容に沿って進めます。

https://docs.snowflake.com/en/user-guide/admin-security-privatelink

AWS CLI で以下のコマンドを実行し一時的な資格情報を発行します。

aws sts get-federation-token --name username

出力は以下のようになります。

{
    "Credentials": {
        "AccessKeyId": "XXXXX",
        "SecretAccessKey": "XXXXX",
        "SessionToken": "XXXXX",
        "Expiration": "XXXXX"
    },
    "FederatedUser": {
        "FederatedUserId": "<aws_id>:username",
        "Arn": "arn:aws:sts::<aws_id>:federated-user/username"
    },
    "PackedPolicySize": 0
}

続けて Snowflake 側で以下のコマンドを実行します。(実行には ACCOUNTADMIN 権限が必要)

USE ROLE ACCOUNTADMIN;
SELECT SYSTEM$AUTHORIZE_PRIVATELINK ( '<aws_id>' , '<federated_token>' );

<aws_id> にはaws sts get-federation-token で取得できる AWS アカウントのID、<federated_token> にはaws sts get-federation-token の出力を指定します。

SELECT SYSTEM$AUTHORIZE_PRIVATELINK ( '<aws_id>' , '{
    "Credentials": {
        "AccessKeyId": "XXXXX",
        "SecretAccessKey": "XXXXX",
        "SessionToken": "XXXXX",
        "Expiration": "XXXXX"
    },
    "FederatedUser": {
        "FederatedUserId": "<aws_id>:username",
        "Arn": "arn:aws:sts::<aws_id>:federated-user/username"
    },
    "PackedPolicySize": 0
}' );

コマンド実行後の以下の出力となれば問題ありません。

image 1

AWS VPC環境の設定

VPC エンドポイント (VPCE) の作成と設定

はじめに Snowflake 側で SYSTEM$GET_PRIVATELINK_CONFIG を実行しprivatelink-vpce-id値を取得します。(実行には ACCOUNTADMIN 権限が必要)

USE ROLE ACCOUNTADMIN;
SELECT SYSTEM$GET_PRIVATELINK_CONFIG();

出力は以下のようになっており後述する手順で使用します。

{
"regionless-snowsight-privatelink-url":"app-<orgname>-<account_name>.privatelink.snowflakecomputing.com",
"privatelink-account-name":"<account_identifier>.us-east-1.privatelink",
"privatelink-vpce-id":"com.amazonaws.vpce.us-east-1.vpce-svc-XXXXX",
"snowsight-privatelink-url":"app.us-east-1.privatelink.snowflakecomputing.com",
"regionless-privatelink-ocsp-url":"ocsp.<orgname>-<account_name>.privatelink.snowflakecomputing.com",
"privatelink-account-url":"<account_identifier>.us-east-1.privatelink.snowflakecomputing.com",
"regionless-privatelink-account-url":"<orgname>-<account_name>.privatelink.snowflakecomputing.com",
"privatelink_ocsp-url":"ocsp.<account_identifier>.us-east-1.privatelink.snowflakecomputing.com"
}

AWS 側で以下の設定で VPC エンドポイントを作成します。

  • サービスカテゴリ
    • その他のエンドポイントサービス
  • サービス名
    • SYSTEM$GET_PRIVATELINK_CONFIG の出力の内privatelink-vpce-id の値

image 2

サービスの検証ができたら、エンドポイントを作成する VPC を指定し、インスタンスがあるサブネット、セキュリティグループを指定してエンドポイントを作成します。

セキュリティグループでは、AWS環境(VPC)から Snowflake に接続を行うソースからのポート 80 と 443 の通信を許可します。ここでは接続を行う EC2 に関連付けたセキュリティグループを指定しました。

image 3

エンドポイントが作成されたら後述する手順で使用するために DNS 名を確認しておきます。

image 4

VPCネットワークを構成する

PrivateLink 経由で Snowflake にアクセスするために Amazon Route 53 の構成を行います。
具体的には、以下の構成で新しいホストゾーンを作成します。

  • ドメイン名:privatelink.snowflakecomputing.com
  • タイプ:プライベートホストゾーン

image 5

VPC は Snowflake に接続を行う VPC を関連付けます。

DNS ホストゾーンに CNAME レコードを作成

ホストゾーンを作成後、以下の内容で CNAME レコードを作成ます。値はいずれも上記の手順で作成した VPC エンドポイントの DNS 名です。

レコード名 内容
<account_identifier>.us-east-1.privatelink.snowflakecomputing.com privatelink-account-url
app.us-east-1.privatelink.snowflakecomputing.com snowsight-privatelink-url
ocsp.<account_identifier>.us-east-1.privatelink.snowflakecomputing.com privatelink_ocsp-url
<orgname>-<account_name>.privatelink.snowflakecomputing.com regionless-privatelink-account-url
app-<orgname>-<account_name>.privatelink.snowflakecomputing.com regionless-snowsight-privatelink-ur
ocsp.<orgname>-<account_name>.privatelink.snowflakecomputing.com regionless-privatelink-ocsp-url

Snowflake にアクセスする際は、アカウントロケーターを使用するものと組織名・アカウント名を使用するものの 2 種類の URL を使用できます。プライベートアクセス用の URL も同様に 2 種類用意されています。

組織名を使用しない場合はリージョンのない URL のレコードを登録せずとも Snowflake にアクセスできるようにはなりますが、完全な機能を確保しつつ、将来的なアップデートの可能性に備えるために、いずれも含めるのがよいと考えています。

また、公式ドキュメントでは、以下の URL についてもレコード登録するように記載があります。本記事の検証環境では SYSTEM$GET_PRIVATELINK_CONFIG の出力に含まれていない内容なのでスキップしていますが、クライアントリダイレクトを構成している場合にはこちらの URL も追加表示されるのでレコードとして追加します。

  • privatelink-connection-ocsp-urls
  • privatelink-connection-urls

Route 53 の設定については以下でも解説されているため、あわせてご参照ください。

https://community.snowflake.com/s/article/How-to-configure-the-AWS-DNS-service-Route-53-to-access-Snowflake-via-a-PrivateLink

接続確認

レコードの作成後、プライベートサブネット内のインスタンスから、プライベート接続用の URL で Snowflake にアクセスしてみます。

ログイン画面

image 6

ログイン後

image 7

また、接続の検証には SnowCD も使用できます。ここではSELECT SYSTEM$ALLOWLIST_PRIVATELINK() の出力を JSON 等で保存し VPC 内のインスタンスから実行すると以下のような結果となりました。

実行結果:アカウントロケーターを使用する URL のみレコード登録後

Performing 31 checks for 11 hosts
lookup ocsp.<orgname>-<account_name>.privatelink.snowflakecomputing.com: no such host
lookup <orgname>-<account_name>.privatelink.snowflakecomputing.com: no such host
lookup app-<orgname>-<account_name>.privatelink.snowflakecomputing.com: no such host

Check for 3 hosts failed, display as follow:
==============================================
Host: <orgname>-<account_name>.privatelink.snowflakecomputing.com
Port: 443
Type: SNOWFLAKE_DEPLOYMENT_REGIONLESS
Failed Check: DNS Check
Error: lookup <orgname>-<account_name>.privatelink.snowflakecomputing.com: no such host
Suggestion: Check your configuration on DNS server

==============================================
Host: ocsp.<orgname>-<account_name>.privatelink.snowflakecomputing.com
Port: 80
Type: OCSP_CACHE_REGIONLESS
Failed Check: DNS Check
Error: lookup ocsp.<orgname>-<account_name>.privatelink.snowflakecomputing.com: no such host
Suggestion: Check your configuration on DNS server

==============================================
Host: app-<orgname>-<account_name>.privatelink.snowflakecomputing.com
Port: 443
Type: SNOWSIGHT_DEPLOYMENT_REGIONLESS
Failed Check: DNS Check
Error: lookup app-<orgname>-<account_name>.privatelink.snowflakecomputing.com: no such host
Suggestion: Check your configuration on DNS server

上記の場合、組織名・アカウント名を使用する URL も SYSTEM$ALLOWLIST_PRIVATELINK の出力には含まれるものの、名前解決できないためにエラーとなっているようです。
組織名・アカウント名のレコードを追加後は以下の出力となりました。

Performing 31 checks for 11 hosts

Check for 1 hosts failed, display as follow:
==============================================
Host: ocsp.<orgname>-<account_name>.privatelink.snowflakecomputing.com
Port: 80
Type: OCSP_CACHE_REGIONLESS
Failed Check: HTTP checker
Error: Invalid http code received: 403 Forbidden
Suggestion: Check the connection to your http host or transparent Proxy

Windows 版の SnowCD 1.0.5 を使用したのですが、これは既知のエラーのようですのでそのまま進めました。

https://community.snowflake.com/s/article/SnowCD-fails-check-for-regionless-accounts-with-PrivateLink-enabled

内部ステージへのアクセスを構成する

次に、VPC 内のインスタンスから Snowflake の内部ステージ(S3)へのアクセスについてです。内部ステージへのアクセス方法は大きく以下にわかれます。

  1. ゲートウェイ型の VPC エンドポイントを使用
  2. インターフェース型の VPC エンドポイントを使用
  3. 上記以外の方法によるアクセス(NAT ゲートウェイ などを使用)

本記事ではこのうち 1・2 について扱います。

ゲートウェイ型の VPC エンドポイントを使用

こちらは PrivateLink を使用しない方法です。ゲートウェイ型のエンドポイントとして以下の特徴があります。

  • AWS 側で追加料金なしで使用可能
  • パブリック IP アドレスで解決

インターフェース型のエンドポイントとの違いもあわせて、特徴は以下に記載があります。ゲートウェイ型のエンドポイントを使用した場合でも、ネットワークトラフィックは AWS ネットワーク上に残ります。

https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/userguide/privatelink-interface-endpoints.html#types-of-vpc-endpoints-for-s3#types-of-vpc-endpoints-for-s3

ここでは、前提条件として VPC 作成時にあわせて S3 へのゲートウェイ型のエンドポイントを作成しているので、追加の構成は不要で接続確認のみ行います。

Snowflake で以下のコマンドを実行してみます。

SELECT SYSTEM$ALLOWLIST();

以下は出力の一部ですが、Snowflake 管理の Amazon S3 バケットへの URL できます。

{"host":"sfc-xxx-customer-stage.s3.amazonaws.com","port":443,"type":"STAGE"},
{"host":"sfc-xxx-customer-stage.s3.us-east-1.amazonaws.com","port":443,"type":"STAGE"}

VPC 内のインスタンスから名前解決を行うとパブリック IP アドレスに解決されます。

> Test-NetConnection -ComputerName sfc-xxx-customer-stage.s3.us-east-1.amazonaws.com -Port 443

ComputerName     : sfc-xxx-customer-stage.s3.us-east-1.amazonaws.com
RemoteAddress    : 52.xx.xx.xx
RemotePort       : 443
InterfaceAlias   : Ethernet 2
SourceAddress    : 10.xx.xx.xx
TcpTestSucceeded : True

また、インスタンスから S3 への PUT も可能か確認しておきます。

>put file://C:\Users\path\products_2.csv @stg_test;
+----------------+-------------------+-------------+-------------+--------------------+--------------------+----------+---------+
| source         | target            | source_size | target_size | source_compression | target_compression | status   | message |
|----------------+-------------------+-------------+-------------+--------------------+--------------------+----------+---------|
| products_2.csv | products_2.csv.gz |         306 |         221 | NONE               | GZIP               | UPLOADED |         |
+----------------+-------------------+-------------+-------------+--------------------+--------------------+----------+---------+
1 Row(s) produced. Time Elapsed: 1.003s

インターフェース型の VPC エンドポイントを使用

こちらは Snowflake 側も含めて追加の接続設定が必要です。ドキュメントは以下に記載があります。

https://docs.snowflake.com/en/user-guide/private-internal-stages-aws

上述のドキュメントにも記載がありますが、主な特徴は以下です。

  • プライベート IP アドレスで解決
  • オンプレミスからのアクセスを許可する

以降で接続設定手順を見ていきます。

1.ENABLE_INTERNAL_STAGES_PRIVATELINK パラメータを有効化

はじめに、Snowflake 側で以下のコマンドを実行し ENABLE_INTERNAL_STAGES_PRIVATELINK パラメータを有効化します。

USE ROLE ACCOUNTADMIN;
ALTER ACCOUNT SET enable_internal_stages_privatelink = True;

2.Snowflake アカウントの内部ステージの URL を取得

上記のコマンド実行後、続けてSnowflake 側で SYSTEM$GET_PRIVATELINK_CONFIG コマンドを実行し、S3 へのアクセスプライベート接続設定に使用する URL を取得します。

SELECT system$get_privatelink_config();

以下で表形式での取得もできます。このうち KEY がprivatelink-internal-stage の値を使用します。

SELECT key, value FROM TABLE(flatten(input=>parse_json(system$get_privatelink_config())));
"sfc-xxx-customer-stage.s3.us-east-1.amazonaws.com"

3.S3 インターフェイスエンドポイントを作成

次に AWS 側でインターフェース型の S3 エンドポイントを作成します。

image 8

エンドポイントの作成先にはインスタンスを構成した VPC を選択し、サブネットもインスタンスを構成したプライベートサブネットを指定します。セキュリティグループは、インスタンスに関連付けたセキュリティグループからのポート80,443 のアクセスを許可しました。

4.DNS ホストゾーンにレコードを追加

次に DNS 設定を行い、VPC 内のクライアント (ブラウザ、ドライバーなど) が内部ステージ URL (sfc-xxx-customer-stage.s3.us-east-1.amazonaws.com) にアクセスする際に、作成した S3 インターフェースエンドポイントを経由してルーティングされるようにします。

この際の注意点として、以下の「6. DNS configuration」に記載があるように VPC から Snowflake 内部ステージ以外の S3 バケットにも接続する場合は、<bucket>.s3.<region>.amazonaws.com という名称のプライベートホストゾーンを作成します。

https://community.snowflake.com/s/article/HOW-TO-configure-private-connectivity-to-aws-internal-stages

ここでは上記の通り、他のバケットにもアクセスする想定でsystem$get_privatelink_config の出力であるprivatelink-internal-stage キーの値sfc-xxx-customer-stage.s3.us-east-1.amazonaws.com でプライベートホストゾーンを作成しました。VPC はインスタンスを作成した VPC を関連付けます。

image 9

レコードには、S3 インターフェースエンドポイントの プライベート IP アドレスを値として指定する A レコードを作成します。

プライベート IP アドレスの取得

image 10

A レコードの作成

image 11

以上で DNS 設定は完了です。

5.構成のテスト

上記の構成後、VPC 内のインスタンスから Snowflake の内部ステージ URL に対して接続確認を行います。出力は以下のようになり、プライベートIPアドレスに解決されます。

> Test-NetConnection -ComputerName sfc-xxx-customer-stage.s3.us-east-1.amazonaws.com -Port 443                                                                                                                                          
ComputerName     : sfc-xxx-customer-stage.s3.us-east-1.amazonaws.com
RemoteAddress    : 10.xx.xx.xx
RemotePort       : 443
InterfaceAlias   : Ethernet 2
SourceAddress    : 10.0.133.240
TcpTestSucceeded : True

S3 に対して PUT コマンドも実行可能か確認しておきます。

>put file://C:\Users\path\products_3.csv @stg_test;
+----------------+-------------------+-------------+-------------+--------------------+--------------------+----------+---------+
| source         | target            | source_size | target_size | source_compression | target_compression | status   | message |
|----------------+-------------------+-------------+-------------+--------------------+--------------------+----------+---------|
| products_3.csv | products_3.csv.gz |         306 |         221 | NONE               | GZIP               | UPLOADED |         |
+----------------+-------------------+-------------+-------------+--------------------+--------------------+----------+---------+
1 Row(s) produced. Time Elapsed: 1.617s

パブリックアクセスのブロック

PrivateLink 構成の有無に関わらず Snowflake ではネットワークポリシーやネットワークルールによるアクセス制御が可能です。

また、ENFORCE_NETWORK_RULES_FOR_INTERNAL_STAGES パラメータを有効にすることで内部ステージへのアクセスも制御可能です。

※このパラメータを有効化しないと内部ステージへのアクセスは保護されません。

https://docs.snowflake.com/en/user-guide/network-policies#protecting-internal-stages-on-aws

ここでは以下の手順で、VPC 内のインスタンスと特定の IP アドレスからのサービス・内部ステージへのアクセスを許可し、その他はブロックする設定としてみます。

--ネットワークルール管理用DBを作成
USE ROLE SYSADMIN;
CREATE DATABASE security;
CREATE SCHEMA network_rules;
USE SCHEMA security.network_rules;

--AWS S3 エンドポイントから内部ステージへのトラフィックを許可またはブロックするために使用されるネットワークルールを作成
CREATE NETWORK RULE s3_interface_gateway_netoworkrule
  TYPE = AWSVPCEID
  VALUE_LIST = ('vpce-xxxxx')
  MODE = INTERNAL_STAGE
  COMMENT = 's3 interface endpoint';

--AWS エンドポイントからから Snowflake サービスへのトラフィックを許可またはブロックするために使用されるネットワークルールを作成
CREATE NETWORK RULE allow_vpceid_access
  MODE = INGRESS
  TYPE = AWSVPCEID
  VALUE_LIST = ('vpce-xxxxx');

--特定の IP アドレスから Snowflake サービスおよび内部ステージへのトラフィックを許可またはブロックするために使用されるネットワークルールを作成
CREATE NETWORK RULE myip_netoworkrule
  TYPE = IPV4
  VALUE_LIST = ('XX.XX.XX.XX/32')
  COMMENT ='myip';

--ネットワークポリシーを作成
USE ROLE SECURITYADMIN;
CREATE NETWORK POLICY mypolicy ALLOWED_NETWORK_RULE_LIST
('allow_vpceid_access','s3_interface_gateway_netoworkrule','myip_netoworkrule');
DESC NETWORK POLICY mypolicy;

--アカウントレベルでネットワークポリシーを有効化
ALTER ACCOUNT SET NETWORK_POLICY = mypolicy;

--ENFORCE_NETWORK_RULES_FOR_INTERNAL_STAGES パラメータを有効化
USE ROLE ACCOUNTADMIN;
ALTER ACCOUNT SET ENFORCE_NETWORK_RULES_FOR_INTERNAL_STAGES = true;
SHOW PARAMETERS IN ACCOUNT;
SELECT * FROM TABLE(RESULT_SCAN(-1)) WHERE $1 = 'ENFORCE_NETWORK_RULES_FOR_INTERNAL_STAGES';

この状態で許可リストにないネットワークから Snowflake アカウントにアクセスすると下図の表示になります。

image 12

許可したネットワークや VPC 内のインスタンスからは以下の通り引き続きアクセス可能です。

S3 へのアクセス検証は GET_PRESIGNED_URL による事前署名付き URL へのアクセスで行いました。

https://dev.classmethod.jp/articles/try-snowflake-pre-signed-url/

ネットワーク ポリシーは GET_PRESIGNED_URL によって生成された署名済み URL に対しても動作します。

https://docs.snowflake.com/en/release-notes/bcr-bundles/2024_03/bcr-1558

上記の設定ではENFORCE_NETWORK_RULES_FOR_INTERNAL_STAGES パラメータを有効化しているので、この状態でアクセス可能なネットワークから以下のコマンドを実行し、事前署名付き URL を発行します。

SELECT GET_PRESIGNED_URL(@STG_TEST, 'products.csv');

許可しているネットワークから例えばブラウザ経由でこの URL にアクセスすると、CSV ファイルをダウンロード可能です。
許可していないネットワークの場合は、以下のようにアクセスが拒否されます。

image 13

再度パラメータを無効化し、URL を発行すると、依然として Snowsight へのアクセスはできませんがステージへのアクセスは可能となります。

curl 'https://sfc-xxx-customer-stage.s3.us-east-1.amazonaws.com/xxx/stages/xxx/products.csv?xxx'
product_id,product_name,category,price,stock_quantity,release_date
101,Smartphone,Electronics,599.99,50,2024-05-10
102,Laptop,Electronics,899.99,30,2024-06-15
103,Tablet,Electronics,399.99,80,2024-07-01
104,Headphones,Accessories,199.99,100,2024-08-20
105,Smartwatch,Accessories,249.99,60,2024-08-25

許可リストとブロックリストの相互作用

またネットワークルール設定時の注意点として「異なるタイプの識別子が自動的にブロックされるわけではない」ためご注意ください。例えば以下のようにネットワークルールのタイプとしてAWSVPCEID を指定したものを作成し、ポリシーのALLOWED_NETWORK_RULE_LIST に割り当てたとします。

CREATE NETWORK RULE allow_vpceid_access
  MODE = INGRESS
  TYPE = AWSVPCEID
  VALUE_LIST = ('vpce-xxxxx');

CREATE NETWORK POLICY mypolicy 
	ALLOWED_NETWORK_RULE_LIST ('allow_vpceid_access');

この場合、タイプの異なる IPV4 アドレスでのアクセスは可能なままとなります。IPV4 アドレスからのアクセスも制限する場合は、タイプ IPV4 とするネットワークルールを追加する必要があります。詳細は以下をご参照ください。

https://docs.snowflake.com/ja/user-guide/network-policies#interaction-between-allowed-lists-and-blocked-lists

組織で複数アカウントを使用し内部ステージにアクセスする場合

以下に記載がありますが、組織で複数の Snowflake アカウントを使用しており、インターフェース型のエンドポイントで内部ステージにアクセスする場合は、S3_STAGE_VPCE_DNS_NAME パラメータの値に S3 インターフェースエンドポイントの DNS 名を指定することで、各アカウントの内部ステージへのアクセス時に、それぞれの専用のインターフェースエンドポイントを使用可能となります。これにより、AWS PrivateLink での接続時のネットワークトラフィックを分離することが可能です。

https://docs.snowflake.com/en/user-guide/private-internal-stages-aws#label-aws-privatelink-internal-stage-network-isolation

さいごに

AWS 環境の Snowflake における内部ステージも含めた PrivateLink 構成の手順をまとめました。こちらの内容が何かの参考になれば幸いです。

参考

https://docs.aws.amazon.com/ja_jp/vpc/latest/privatelink/gateway-endpoints.html

https://aws.amazon.com/jp/vpc/faqs/

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.